home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / Portable Patmos / src / portable kernel / mac / vkprintf.c.old < prev    next >
Encoding:
Text File  |  1994-11-24  |  20.2 KB  |  884 lines  |  [TEXT/KAHL]

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Chris Torek.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. static char sccsid[] = "@(#)vfprintf.c    5.47 (Berkeley) 3/22/91";
  39. #endif /* LIBC_SCCS and not lint */
  40.  
  41. /*
  42.  * Actual printf innards.
  43.  *
  44.  * This code is large and complicated...
  45.  */
  46.  
  47. #include <sys/types.h>
  48. #include <math.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51. #if __STDC__
  52. #include <stdarg.h>
  53. #else
  54. #include <varargs.h>
  55. #endif
  56. #include "local.h"
  57. #include "fvwrite.h"
  58.  
  59. /*
  60.  * Define FLOATING_POINT to get floating point.
  61.  * Define CSH to get a csh-specific version (grr).
  62.  */
  63. #ifndef CSH
  64. #define    FLOATING_POINT
  65. #endif
  66.  
  67. /* end of configuration stuff */
  68.  
  69. static double modf(double value, double *iptr)
  70.     {
  71.     long x = (int) value;
  72.     if (x >= 0)
  73.         {
  74.         if (value < (double)x) x--;
  75.         }
  76.     else
  77.         {
  78.         if (value > (double)x) x++;
  79.         }
  80.     *iptr = x;
  81.     return value - *iptr;
  82.     }
  83.  
  84. static int __sprint(char *output_string, register struct __suio *uio)
  85. {
  86.     register char *p;
  87.     register int n, ch, iovcnt;
  88.     register struct __siov *iov;
  89.  
  90.     iov = uio->uio_iov;
  91.     for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) 
  92.         {
  93.         strncat(output_string, iov->iov_base, iov->iov_len);
  94.         }
  95.     uio->uio_resid = 0;
  96.     uio->uio_iovcnt = 0;
  97.     return (0);
  98. }
  99.  
  100.  
  101. #ifdef FLOATING_POINT
  102. #include "floatio.h"
  103.  
  104. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  105. #define    DEFPREC        6
  106.  
  107. static int cvt();
  108.  
  109. #else /* no FLOATING_POINT */
  110.  
  111. #define    BUF        40
  112.  
  113. #endif /* FLOATING_POINT */
  114.  
  115.  
  116. /*
  117.  * Macros for converting digits to letters and vice versa
  118.  */
  119. #define    to_digit(c)    ((c) - '0')
  120. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  121. #define    to_char(n)    ((n) + '0')
  122.  
  123. /*
  124.  * Flags used during conversion.
  125.  */
  126. #define    LONGINT        0x01        /* long integer */
  127. #define    LONGDBL        0x02        /* long double; unimplemented */
  128. #define    SHORTINT    0x04        /* short integer */
  129. #define    ALT        0x08        /* alternate form */
  130. #define    LADJUST        0x10        /* left adjustment */
  131. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  132. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  133.  
  134. int
  135. vkprintf(fp, fmt0, ap)
  136.     char *fp;
  137.     const char *fmt0;
  138. #if tahoe
  139.  register /* technically illegal, since we do not know what type va_list is */
  140. #endif
  141.     va_list ap;
  142. {
  143.     register char *fmt;    /* format string */
  144.     register int ch;    /* character from fmt */
  145.     register int n;        /* handy integer (short term usage) */
  146.     register char *cp;    /* handy char pointer (short term usage) */
  147.     register struct __siov *iovp;/* for PRINT macro */
  148.     register int flags;    /* flags as above */
  149.     int ret;        /* return value accumulator */
  150.     int width;        /* width from format (%8d), or 0 */
  151.     int prec;        /* precision from format (%.3d), or -1 */
  152.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  153. #ifdef FLOATING_POINT
  154.     char softsign;        /* temporary negative sign for floats */
  155.     double _double;        /* double precision arguments %[eEfgG] */
  156.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  157. #endif
  158.     u_long _ulong;        /* integer arguments %[diouxX] */
  159.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  160.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  161.     int fieldsz;        /* field size expanded by sign, etc */
  162.     int realsz;        /* field size expanded by dprec */
  163.     int size;        /* size of converted field or string */
  164.     char *xdigs;        /* digits for [xX] conversion */
  165. #define NIOV 8
  166.     struct __suio uio;    /* output information: summary */
  167.     struct __siov iov[NIOV];/* ... and individual io vectors */
  168.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  169.     char ox[2];        /* space for 0x hex-prefix */
  170.  
  171.     /*
  172.      * Choose PADSIZE to trade efficiency vs size.  If larger
  173.      * printf fields occur frequently, increase PADSIZE (and make
  174.      * the initialisers below longer).
  175.      */
  176. #define    PADSIZE    16        /* pad chunk size */
  177.     static char blanks[PADSIZE] =
  178.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  179.     static char zeroes[PADSIZE] =
  180.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  181.  
  182.     /*
  183.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  184.      */
  185. #define    PRINT(ptr, len) { \
  186.     iovp->iov_base = (ptr); \
  187.     iovp->iov_len = (len); \
  188.     uio.uio_resid += (len); \
  189.     iovp++; \
  190.     if (++uio.uio_iovcnt >= NIOV) { \
  191.         if (__sprint(fp, &uio)) \
  192.             goto error; \
  193.         iovp = iov; \
  194.     } \
  195. }
  196. #define    PAD(howmany, with) { \
  197.     if ((n = (howmany)) > 0) { \
  198.         while (n > PADSIZE) { \
  199.             PRINT(with, PADSIZE); \
  200.             n -= PADSIZE; \
  201.         } \
  202.         PRINT(with, n); \
  203.     } \
  204. }
  205. #define    FLUSH() { \
  206.     if (uio.uio_resid && __sprint(fp, &uio)) \
  207.         goto error; \
  208.     uio.uio_iovcnt = 0; \
  209.     iovp = iov; \
  210. }
  211.  
  212.     /*
  213.      * To extend shorts properly, we need both signed and unsigned
  214.      * argument extraction methods.
  215.      */
  216. #define    SARG() \
  217.     (flags&LONGINT ? va_arg(ap, long) : \
  218.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  219.         (long)va_arg(ap, int))
  220. #define    UARG() \
  221.     (flags&LONGINT ? va_arg(ap, u_long) : \
  222.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  223.         (u_long)va_arg(ap, u_int))
  224.  
  225.     fmt = (char *)fmt0;
  226.     uio.uio_iov = iovp = iov;
  227.     uio.uio_resid = 0;
  228.     uio.uio_iovcnt = 0;
  229.     ret = 0;
  230.  
  231.     /*
  232.      * Scan the format for conversions (`%' character).
  233.      */
  234.     for (;;) {
  235.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  236.             /* void */;
  237.         if ((n = fmt - cp) != 0) {
  238.             PRINT(cp, n);
  239.             ret += n;
  240.         }
  241.         if (ch == '\0')
  242.             goto done;
  243.         fmt++;        /* skip over '%' */
  244.  
  245.         flags = 0;
  246.         dprec = 0;
  247. #ifdef FLOATING_POINT
  248.         fpprec = 0;
  249. #endif
  250.         width = 0;
  251.         prec = -1;
  252.         sign = '\0';
  253.  
  254. rflag:        ch = *fmt++;
  255. reswitch:    switch (ch) {
  256.         case ' ':
  257.             /*
  258.              * ``If the space and + flags both appear, the space
  259.              * flag will be ignored.''
  260.              *    -- ANSI X3J11
  261.              */
  262.             if (!sign)
  263.                 sign = ' ';
  264.             goto rflag;
  265.         case '#':
  266.             flags |= ALT;
  267.             goto rflag;
  268.         case '*':
  269.             /*
  270.              * ``A negative field width argument is taken as a
  271.              * - flag followed by a positive field width.''
  272.              *    -- ANSI X3J11
  273.              * They don't exclude field widths read from args.
  274.              */
  275.             if ((width = va_arg(ap, int)) >= 0)
  276.                 goto rflag;
  277.             width = -width;
  278.             /* FALLTHROUGH */
  279.         case '-':
  280.             flags |= LADJUST;
  281.             goto rflag;
  282.         case '+':
  283.             sign = '+';
  284.             goto rflag;
  285.         case '.':
  286.             if ((ch = *fmt++) == '*') {
  287.                 n = va_arg(ap, int);
  288.                 prec = n < 0 ? -1 : n;
  289.                 goto rflag;
  290.             }
  291.             n = 0;
  292.             while (is_digit(ch)) {
  293.                 n = 10 * n + to_digit(ch);
  294.                 ch = *fmt++;
  295.             }
  296.             prec = n < 0 ? -1 : n;
  297.             goto reswitch;
  298.         case '0':
  299.             /*
  300.              * ``Note that 0 is taken as a flag, not as the
  301.              * beginning of a field width.''
  302.              *    -- ANSI X3J11
  303.              */
  304.             flags |= ZEROPAD;
  305.             goto rflag;
  306.         case '1': case '2': case '3': case '4':
  307.         case '5': case '6': case '7': case '8': case '9':
  308.             n = 0;
  309.             do {
  310.                 n = 10 * n + to_digit(ch);
  311.                 ch = *fmt++;
  312.             } while (is_digit(ch));
  313.             width = n;
  314.             goto reswitch;
  315. #ifdef FLOATING_POINT
  316.         case 'L':
  317.             flags |= LONGDBL;
  318.             goto rflag;
  319. #endif
  320.         case 'h':
  321.             flags |= SHORTINT;
  322.             goto rflag;
  323.         case 'l':
  324.             flags |= LONGINT;
  325.             goto rflag;
  326.         case 'c':
  327.             *(cp = buf) = va_arg(ap, int);
  328.             size = 1;
  329.             sign = '\0';
  330.             break;
  331.         case 'D':
  332.             flags |= LONGINT;
  333.             /*FALLTHROUGH*/
  334.         case 'd':
  335.         case 'i':
  336.             _ulong = SARG();
  337.             if ((long)_ulong < 0) {
  338.                 _ulong = -_ulong;
  339.                 sign = '-';
  340.             }
  341.             base = DEC;
  342.             goto number;
  343. #ifdef FLOATING_POINT
  344.         case 'e':
  345.         case 'E':
  346.         case 'f':
  347.         case 'g':
  348.         case 'G':
  349.             _double = va_arg(ap, double);
  350.             /* do this before tricky precision changes */
  351.             /*
  352.              * don't do unrealistic precision; just pad it with
  353.              * zeroes later, so buffer size stays rational.
  354.              */
  355.             if (prec > MAXFRACT) {
  356.                 if (ch != 'g' && ch != 'G' || (flags&ALT))
  357.                     fpprec = prec - MAXFRACT;
  358.                 prec = MAXFRACT;
  359.             } else if (prec == -1)
  360.                 prec = DEFPREC;
  361.             /*
  362.              * cvt may have to round up before the "start" of
  363.              * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
  364.              * if the first character is still NUL, it did.
  365.              * softsign avoids negative 0 if _double < 0 but
  366.              * no significant digits will be shown.
  367.              */
  368.             cp = buf;
  369.             *cp = '\0';
  370.             size = cvt(_double, prec, flags, &softsign, ch,
  371.                 cp, buf + sizeof(buf));
  372.             if (softsign)
  373.                 sign = '-';
  374.             if (*cp == '\0')
  375.                 cp++;
  376.             break;
  377. #endif /* FLOATING_POINT */
  378.         case 'n':
  379.             if (flags & LONGINT)
  380.                 *va_arg(ap, long *) = ret;
  381.             else if (flags & SHORTINT)
  382.                 *va_arg(ap, short *) = ret;
  383.             else
  384.                 *va_arg(ap, int *) = ret;
  385.             continue;    /* no output */
  386.         case 'O':
  387.             flags |= LONGINT;
  388.             /*FALLTHROUGH*/
  389.         case 'o':
  390.             _ulong = UARG();
  391.             base = OCT;
  392.             goto nosign;
  393.         case 'p':
  394.             /*
  395.              * ``The argument shall be a pointer to void.  The
  396.              * value of the pointer is converted to a sequence
  397.              * of printable characters, in an implementation-
  398.              * defined manner.''
  399.              *    -- ANSI X3J11
  400.              */
  401.             /* NOSTRICT */
  402.             _ulong = (u_long)va_arg(ap, void *);
  403.             base = HEX;
  404.             xdigs = "0123456789abcdef";
  405.             flags |= HEXPREFIX;
  406.             ch = 'x';
  407.             goto nosign;
  408.         case 's':
  409.             if ((cp = va_arg(ap, char *)) == NULL)
  410.                 cp = "(null)";
  411.             if (prec >= 0) {
  412.                 /*
  413.                  * can't use strlen; can only look for the
  414.                  * NUL in the first `prec' characters, and
  415.                  * strlen() will go further.
  416.                  */
  417.                 char *p = memchr(cp, 0, prec);
  418.  
  419.                 if (p != NULL) {
  420.                     size = p - cp;
  421.                     if (size > prec)
  422.                         size = prec;
  423.                 } else
  424.                     size = prec;
  425.             } else
  426.                 size = strlen(cp);
  427.             sign = '\0';
  428.             break;
  429.         case 'U':
  430.             flags |= LONGINT;
  431.             /*FALLTHROUGH*/
  432.         case 'u':
  433.             _ulong = UARG();
  434.             base = DEC;
  435.             goto nosign;
  436.         case 'X':
  437.             xdigs = "0123456789ABCDEF";
  438.             goto hex;
  439.         case 'x':
  440.             xdigs = "0123456789abcdef";
  441. hex:            _ulong = UARG();
  442.             base = HEX;
  443.             /* leading 0x/X only if non-zero */
  444.             if (flags & ALT && _ulong != 0)
  445.                 flags |= HEXPREFIX;
  446.  
  447.             /* unsigned conversions */
  448. nosign:            sign = '\0';
  449.             /*
  450.              * ``... diouXx conversions ... if a precision is
  451.              * specified, the 0 flag will be ignored.''
  452.              *    -- ANSI X3J11
  453.              */
  454. number:            if ((dprec = prec) >= 0)
  455.                 flags &= ~ZEROPAD;
  456.  
  457.             /*
  458.              * ``The result of converting a zero value with an
  459.              * explicit precision of zero is no characters.''
  460.              *    -- ANSI X3J11
  461.              */
  462.             cp = buf + BUF;
  463.             if (_ulong != 0 || prec != 0) {
  464.                 /*
  465.                  * unsigned mod is hard, and unsigned mod
  466.                  * by a constant is easier than that by
  467.                  * a variable; hence this switch.
  468.                  */
  469.                 switch (base) {
  470.                 case OCT:
  471.                     do {
  472.                         *--cp = to_char(_ulong & 7);
  473.                         _ulong >>= 3;
  474.                     } while (_ulong);
  475.                     /* handle octal leading 0 */
  476.                     if (flags & ALT && *cp != '0')
  477.                         *--cp = '0';
  478.                     break;
  479.  
  480.                 case DEC:
  481.                     /* many numbers are 1 digit */
  482.                     while (_ulong >= 10) {
  483.                         *--cp = to_char(_ulong % 10);
  484.                         _ulong /= 10;
  485.                     }
  486.                     *--cp = to_char(_ulong);
  487.                     break;
  488.  
  489.                 case HEX:
  490.                     do {
  491.                         *--cp = xdigs[_ulong & 15];
  492.                         _ulong >>= 4;
  493.                     } while (_ulong);
  494.                     break;
  495.  
  496.                 default:
  497.                     cp = "bug in vfprintf: bad base";
  498.                     size = strlen(cp);
  499.                     goto skipsize;
  500.                 }
  501.             }
  502.             size = buf + BUF - cp;
  503.         skipsize:
  504.             break;
  505.         default:    /* "%?" prints ?, unless ? is NUL */
  506.             if (ch == '\0')
  507.                 goto done;
  508.             /* pretend it was %c with argument ch */
  509.             cp = buf;
  510.             *cp = ch;
  511.             size = 1;
  512.             sign = '\0';
  513.             break;
  514.         }
  515.  
  516.         /*
  517.          * All reasonable formats wind up here.  At this point,
  518.          * `cp' points to a string which (if not flags&LADJUST)
  519.          * should be padded out to `width' places.  If
  520.          * flags&ZEROPAD, it should first be prefixed by any
  521.          * sign or other prefix; otherwise, it should be blank
  522.          * padded before the prefix is emitted.  After any
  523.          * left-hand padding and prefixing, emit zeroes
  524.          * required by a decimal [diouxX] precision, then print
  525.          * the string proper, then emit zeroes required by any
  526.          * leftover floating precision; finally, if LADJUST,
  527.          * pad with blanks.
  528.          */
  529.  
  530.         /*
  531.          * compute actual size, so we know how much to pad.
  532.          * fieldsz excludes decimal prec; realsz includes it
  533.          */
  534. #ifdef FLOATING_POINT
  535.         fieldsz = size + fpprec;
  536. #else
  537.         fieldsz = size;
  538. #endif
  539.         if (sign)
  540.             fieldsz++;
  541.         else if (flags & HEXPREFIX)
  542.             fieldsz += 2;
  543.         realsz = dprec > fieldsz ? dprec : fieldsz;
  544.  
  545.         /* right-adjusting blank padding */
  546.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  547.             PAD(width - realsz, blanks);
  548.  
  549.         /* prefix */
  550.         if (sign) {
  551.             PRINT(&sign, 1);
  552.         } else if (flags & HEXPREFIX) {
  553.             ox[0] = '0';
  554.             ox[1] = ch;
  555.             PRINT(ox, 2);
  556.         }
  557.  
  558.         /* right-adjusting zero padding */
  559.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  560.             PAD(width - realsz, zeroes);
  561.  
  562.         /* leading zeroes from decimal precision */
  563.         PAD(dprec - fieldsz, zeroes);
  564.  
  565.         /* the string or number proper */
  566.         PRINT(cp, size);
  567.  
  568. #ifdef FLOATING_POINT
  569.         /* trailing f.p. zeroes */
  570.         PAD(fpprec, zeroes);
  571. #endif
  572.  
  573.         /* left-adjusting padding (always blank) */
  574.         if (flags & LADJUST)
  575.             PAD(width - realsz, blanks);
  576.  
  577.         /* finally, adjust ret */
  578.         ret += width > realsz ? width : realsz;
  579.  
  580.         FLUSH();    /* copy out the I/O vectors */
  581.     }
  582. done:
  583.     FLUSH();
  584. error:
  585.     return (ret);
  586.     /* NOTREACHED */
  587. }
  588.  
  589. #ifdef FLOATING_POINT
  590. #include <math.h>
  591.  
  592. static char *exponent();
  593. static char *round();
  594.  
  595. static int
  596. cvt(number, prec, flags, signp, fmtch, startp, endp)
  597.     double number;
  598.     register int prec;
  599.     int flags;
  600.     char *signp;
  601.     int fmtch;
  602.     char *startp, *endp;
  603. {
  604.     register char *p, *t;
  605.     register double fract;
  606.     int dotrim, expcnt, gformat;
  607.     double integer, tmp;
  608.  
  609.     dotrim = expcnt = gformat = 0;
  610.     if (number < 0) {
  611.         number = -number;
  612.         *signp = '-';
  613.     } else
  614.         *signp = 0;
  615.  
  616.     fract = modf(number, &integer);
  617.  
  618.     /* get an extra slot for rounding. */
  619.     t = ++startp;
  620.  
  621.     /*
  622.      * get integer portion of number; put into the end of the buffer; the
  623.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  624.      */
  625.     for (p = endp - 1; integer; ++expcnt) {
  626.         tmp = modf(integer / 10, &integer);
  627.         *p-- = to_char((int)((tmp + .01) * 10));
  628.     }
  629.     switch (fmtch) {
  630.     case 'f':
  631.         /* reverse integer into beginning of buffer */
  632.         if (expcnt)
  633.             for (; ++p < endp; *t++ = *p);
  634.         else
  635.             *t++ = '0';
  636.         /*
  637.          * if precision required or alternate flag set, add in a
  638.          * decimal point.
  639.          */
  640.         if (prec || flags&ALT)
  641.             *t++ = '.';
  642.         /* if requires more precision and some fraction left */
  643.         if (fract) {
  644.             if (prec)
  645.                 do {
  646.                     fract = modf(fract * 10, &tmp);
  647.                     *t++ = to_char((int)tmp);
  648.                 } while (--prec && fract);
  649.             if (fract)
  650.                 startp = round(fract, (int *)NULL, startp,
  651.                     t - 1, (char)0, signp);
  652.         }
  653.         for (; prec--; *t++ = '0');
  654.         break;
  655.     case 'e':
  656.     case 'E':
  657. eformat:    if (expcnt) {
  658.             *t++ = *++p;
  659.             if (prec || flags&ALT)
  660.                 *t++ = '.';
  661.             /* if requires more precision and some integer left */
  662.             for (; prec && ++p < endp; --prec)
  663.                 *t++ = *p;
  664.             /*
  665.              * if done precision and more of the integer component,
  666.              * round using it; adjust fract so we don't re-round
  667.              * later.
  668.              */
  669.             if (!prec && ++p < endp) {
  670.                 fract = 0;
  671.                 startp = round((double)0, &expcnt, startp,
  672.                     t - 1, *p, signp);
  673.             }
  674.             /* adjust expcnt for digit in front of decimal */
  675.             --expcnt;
  676.         }
  677.         /* until first fractional digit, decrement exponent */
  678.         else if (fract) {
  679.             /* adjust expcnt for digit in front of decimal */
  680.             for (expcnt = -1;; --expcnt) {
  681.                 fract = modf(fract * 10, &tmp);
  682.                 if (tmp)
  683.                     break;
  684.             }
  685.             *t++ = to_char((int)tmp);
  686.             if (prec || flags&ALT)
  687.                 *t++ = '.';
  688.         }
  689.         else {
  690.             *t++ = '0';
  691.             if (prec || flags&ALT)
  692.                 *t++ = '.';
  693.         }
  694.         /* if requires more precision and some fraction left */
  695.         if (fract) {
  696.             if (prec)
  697.                 do {
  698.                     fract = modf(fract * 10, &tmp);
  699.                     *t++ = to_char((int)tmp);
  700.                 } while (--prec && fract);
  701.             if (fract)
  702.                 startp = round(fract, &expcnt, startp,
  703.                     t - 1, (char)0, signp);
  704.         }
  705.         /* if requires more precision */
  706.         for (; prec--; *t++ = '0');
  707.  
  708.         /* unless alternate flag, trim any g/G format trailing 0's */
  709.         if (gformat && !(flags&ALT)) {
  710.             while (t > startp && *--t == '0');
  711.             if (*t == '.')
  712.                 --t;
  713.             ++t;
  714.         }
  715.         t = exponent(t, expcnt, fmtch);
  716.         break;
  717.     case 'g':
  718.     case 'G':
  719.         /* a precision of 0 is treated as a precision of 1. */
  720.         if (!prec)
  721.             ++prec;
  722.         /*
  723.          * ``The style used depends on the value converted; style e
  724.          * will be used only if the exponent resulting from the
  725.          * conversion is less than -4 or greater than the precision.''
  726.          *    -- ANSI X3J11
  727.          */
  728.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  729.             /*
  730.              * g/G format counts "significant digits, not digits of
  731.              * precision; for the e/E format, this just causes an
  732.              * off-by-one problem, i.e. g/G considers the digit
  733.              * before the decimal point significant and e/E doesn't
  734.              * count it as precision.
  735.              */
  736.             --prec;
  737.             fmtch -= 2;        /* G->E, g->e */
  738.             gformat = 1;
  739.             goto eformat;
  740.         }
  741.         /*
  742.          * reverse integer into beginning of buffer,
  743.          * note, decrement precision
  744.          */
  745.         if (expcnt)
  746.             for (; ++p < endp; *t++ = *p, --prec);
  747.         else
  748.             *t++ = '0';
  749.         /*
  750.          * if precision required or alternate flag set, add in a
  751.          * decimal point.  If no digits yet, add in leading 0.
  752.          */
  753.         if (prec || flags&ALT) {
  754.             dotrim = 1;
  755.             *t++ = '.';
  756.         }
  757.         else
  758.             dotrim = 0;
  759.         /* if requires more precision and some fraction left */
  760.         if (fract) {
  761.             if (prec) {
  762.                 do {
  763.                     fract = modf(fract * 10, &tmp);
  764.                     *t++ = to_char((int)tmp);
  765.                 } while(!tmp);
  766.                 while (--prec && fract) {
  767.                     fract = modf(fract * 10, &tmp);
  768.                     *t++ = to_char((int)tmp);
  769.                 }
  770.             }
  771.             if (fract)
  772.                 startp = round(fract, (int *)NULL, startp,
  773.                     t - 1, (char)0, signp);
  774.         }
  775.         /* alternate format, adds 0's for precision, else trim 0's */
  776.         if (flags&ALT)
  777.             for (; prec--; *t++ = '0');
  778.         else if (dotrim) {
  779.             while (t > startp && *--t == '0');
  780.             if (*t != '.')
  781.                 ++t;
  782.         }
  783.     }
  784.     return (t - startp);
  785. }
  786.  
  787. static char *
  788. round(fract, exp, start, end, ch, signp)
  789.     double fract;
  790.     int *exp;
  791.     register char *start, *end;
  792.     char ch, *signp;
  793. {
  794.     double tmp;
  795.  
  796.     if (fract)
  797.         (void)modf(fract * 10, &tmp);
  798.     else
  799.         tmp = to_digit(ch);
  800.     if (tmp > 4)
  801.         for (;; --end) {
  802.             if (*end == '.')
  803.                 --end;
  804.             if (++*end <= '9')
  805.                 break;
  806.             *end = '0';
  807.             if (end == start) {
  808.                 if (exp) {    /* e/E; increment exponent */
  809.                     *end = '1';
  810.                     ++*exp;
  811.                 }
  812.                 else {        /* f; add extra digit */
  813.                 *--end = '1';
  814.                 --start;
  815.                 }
  816.                 break;
  817.             }
  818.         }
  819.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  820.     else if (*signp == '-')
  821.         for (;; --end) {
  822.             if (*end == '.')
  823.                 --end;
  824.             if (*end != '0')
  825.                 break;
  826.             if (end == start)
  827.                 *signp = 0;
  828.         }
  829.     return (start);
  830. }
  831.  
  832. static char *
  833. exponent(p, exp, fmtch)
  834.     register char *p;
  835.     register int exp;
  836.     int fmtch;
  837. {
  838.     register char *t;
  839.     char expbuf[MAXEXP];
  840.  
  841.     *p++ = fmtch;
  842.     if (exp < 0) {
  843.         exp = -exp;
  844.         *p++ = '-';
  845.     }
  846.     else
  847.         *p++ = '+';
  848.     t = expbuf + MAXEXP;
  849.     if (exp > 9) {
  850.         do {
  851.             *--t = to_char(exp % 10);
  852.         } while ((exp /= 10) > 9);
  853.         *--t = to_char(exp);
  854.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  855.     }
  856.     else {
  857.         *p++ = '0';
  858.         *p++ = to_char(exp);
  859.     }
  860.     return (p);
  861. }
  862. #endif /* FLOATING_POINT */
  863.  
  864. #if __STDC__
  865. ksprintf(char *str, char const *fmt, ...)
  866. #else
  867. sprintf(str, fmt, va_alist)
  868.     char *str;
  869.     char *fmt;
  870.     va_dcl
  871. #endif
  872. {
  873.     int ret;
  874.     va_list ap;
  875. #if __STDC__
  876.     va_start(ap, fmt);
  877. #else
  878.     va_start(ap);
  879. #endif
  880.     ret = vkprintf(str, fmt, ap);
  881.     va_end(ap);
  882.     return (ret);
  883. }
  884.